#include "e2d/core/render/URPRenderer.h"
#include "e2d/core/render/components.h"
#include "e2d/core/trans/TransformNode.h"
#include "e2d/core/Entity.h"

e2d::URPRenderer::URPRenderer()
{

}

void e2d::URPRenderer::SetInst(std::shared_ptr<e2d::Scene> scene)
{
	m_Scene = scene;
}

void e2d::URPRenderer::BindingPass()
{
}

void e2d::URPRenderer::BeginLightEffect()
{

}

void e2d::URPRenderer::OnLoad()
{

}

void e2d::URPRenderer::OnRender()
{

	for (auto [key, value] : ShaderLoader::m_Effects)
	{
		ForwardRenderPassFixed(key, value);
	}
	for (auto [key, value] : ShaderLoader::m_Effects)
	{
		ForwardRenderPassSkinned(key, value);
	}

}

void e2d::URPRenderer::ForwardRenderPassFixed(const std::string& key, std::shared_ptr<fxcc::graph::opengl3::Effect3d> effect)
{

	auto& buffers = fxcc::graph::opengl3::RenderStates::Inst().m_Buffers;

	effect->Begin();
	effect->SetFixed();

	auto fixedMeshes = m_Scene->GetComponentEntities<e2d::FixedMeshRender>();
	for (auto entity : fixedMeshes) {
		if (!entity->ExistCalculate())continue;

		auto& fixedMeshRender = entity->Get<e2d::FixedMeshRender>();
		if (!fixedMeshRender.m_MaterialView.m_Value)
			continue;

		const auto& material = *fixedMeshRender.m_MaterialView.m_Value;

		if (material.m_EffectToken.m_Key != key) continue;
		auto mesh = fixedMeshRender.GetMesh();

		if (mesh) {

			auto& transformNode = entity->GetOrEmplace<e2d::TransformNode>();

			effect->SetObjData(transformNode.m_World);
			effect->UseMaterial(*fixedMeshRender.m_MaterialView.m_Value);

			mesh->Bind();
			mesh->DrawElementsAuto();
		}
	}
	effect->End();
}

void e2d::URPRenderer::ForwardRenderPassSkinned(const std::string& key, std::shared_ptr<fxcc::graph::opengl3::Effect3d> effect)
{
	auto& buffers = fxcc::graph::opengl3::RenderStates::Inst().m_Buffers;
	effect->SetSkinned();

	auto skinnedMeshes = m_Scene->GetComponentEntities<e2d::SkinnedMeshRender>();
	for (auto entity : skinnedMeshes) {
		if (!entity->ExistCalculate())continue;

		auto& skinnedMeshRender = entity->Get<e2d::SkinnedMeshRender>();
		if (!skinnedMeshRender.m_MaterialView.m_Value)
			continue;

		const auto& material = *skinnedMeshRender.m_MaterialView.m_Value;
		if (material.m_EffectToken.m_Key != key) continue;

		auto mesh = skinnedMeshRender.GetMesh();

		skinnedMeshRender.m_Rendering = mesh.get();

		if (mesh) {

			const auto& transformNode = entity->GetConst<e2d::TransformNode>();

			buffers->SetObjData(transformNode.m_World);
			buffers->SetBoneData(skinnedMeshRender.m_BoneData);
			
			effect->UseMaterial(*skinnedMeshRender.m_MaterialView.m_Value);

			mesh->Bind();
			mesh->DrawElementsAuto();
		}
	}
	effect->End();
}

void e2d::URPRenderer::OnRenderRuntime()
{
}
